﻿using Marmat.Foundation;
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace Marmat.Template.WinForm
{

    /// <summary>
    /// 单据编辑窗体的控制器。
    /// </summary>
    public class DocumentEditFormController : DocumentEditFormController<System.Data.DataRow, System.Data.DataTable>, IDocumentEditFormController
    {
        /// <summary>
        /// 单据管理器
        /// </summary>
        public new DocumentManagement Management { get => (DocumentManagement)base.Management; set => base.Management = value; }

        /// <summary>
        /// 提交自上次调用 AcceptChanges 以来对该数据源进行的所有更改。
        /// </summary>
        public override void AcceptChanges()
        {
            this.DataSource.AcceptChanges();
        }

        /// <summary>
        /// 判断数据是否已被修改。
        /// </summary>
        public override bool HasChanges()
        {
            this.DataSource.EndEdit();
            return this.DataSource.RowState == DataRowState.Added || this.DataSource.RowState == DataRowState.Modified;
        }

        /// <summary>
        /// 创建需要编辑的数据对象。
        /// </summary>
        /// <param name="arguments"></param>
        /// <returns></returns>
        public override DataRow CreateDataObject(params object[] arguments)
        {
            System.Data.DataTable data = this.Management.GetFillSchema().Copy();
            DataRow item = data.NewRow();
            if (item != null)
                data.Rows.Add(item);
            return item;
        }

        /// <summary>
        /// 撤销已更改的记录。
        /// </summary>
        public override void RejectChanges()
        {
            this.DataSource.EndEdit();
            this.DataSource.RejectChanges();
        }

        /// <summary>
        /// 保存
        /// </summary>
        public override void Save()
        {
            this.DataSource.EndEdit();
            DocumentStatusChangeEnum status;
            if (this.Id is null)
                status = DocumentStatusChangeEnum.Insert;
            else
                status = DocumentStatusChangeEnum.Update;

            base.Save();
            //保存成功后更新对象的状态。
            this.DataSource[this.Management.Command.PrimaryName] = this.Id;
            this.DataSource.AcceptChanges();
            this.RefreshText();

            // 广播变更通知
            this.Notification(status);
            //// 通知编辑面板操作成功
            //this.FormPanel.OnSuccess();
        }

        public override void Delete()
        {
            base.Delete();

            // 广播变更通知
            this.Notification(DocumentStatusChangeEnum.Delete);
        }
    }

    /// <summary>
    /// 单据编辑窗体的控制器。
    /// </summary>
    /// <typeparam name="Entity"></typeparam>
    public class DocumentEditFormController<Entity> : DocumentEditFormController<Entity, Entity[]>, IDocumentEditFormController<Entity>, IEditFormDisplayText<Entity> where Entity : class, new()
    {
        /// <summary>
        /// 单据管理器
        /// </summary>
        public new DocumentManagement<Entity> Management { get => (DocumentManagement<Entity>)base.Management; set => base.Management = value; }


        public override void AcceptChanges()
        {
            ObjectConversionFactory.StorageObject(this.DataSource);
        }

        /// <summary>
        /// 创建临时数据,用于新增单据时的默认实例。
        /// </summary>
        /// <param name="arguments">参数</param>
        /// <returns></returns>
        public override Entity CreateDataObject(params object[] arguments)
        {
            this.DataSource = new Entity();
            ObjectConversionFactory.StorageObject(this.DataSource);
            return this.DataSource;
        }

        /// <summary>
        /// 加载需要编辑的数据对象。
        /// </summary>
        /// <param name="arguments"></param>
        public override void LoadDataObject(params object[] arguments)
        {
            base.LoadDataObject(arguments);
            ObjectConversionFactory.StorageObject(this.DataSource);
        }

        /// <summary>
        /// 判断数据是否已被修改。
        /// </summary> 
        public override bool HasChanges()
        {
            if (this.Management.Command is IDocumentCommandObjectConversionProvider provider)
            {
                var conversion = provider.GetConversion();
                return ObjectConversionFactory.HasChanges(this.DataSource, conversion);
            }
            else
            {
                Entity oldInstance = ObjectConversionFactory.GetObject(this.DataSource);
                Entity newInstance = this.DataSource;
                var oldString = Newtonsoft.Json.JsonConvert.SerializeObject(oldInstance);
                var newString = Newtonsoft.Json.JsonConvert.SerializeObject(newInstance);
                return !string.Equals(oldString, newString);
            }
        }

        /// <summary>
        /// 保存。
        /// </summary>
        public override void Save()
        {
            DocumentStatusChangeEnum status;
            if (this.Id is null)
                status = DocumentStatusChangeEnum.Insert;
            else
                status = DocumentStatusChangeEnum.Update;

            base.Save();
            Type type = this.DataSource.GetType();
            MemberInfo member = type.GetMember(this.Management.Command.PrimaryName).First();
            if (member is FieldInfo field)
                field.SetValue(this.DataSource, System.Convert.ChangeType(this.Id, field.FieldType));
            else if (member is PropertyInfo property)
                property.SetValue(this.DataSource, System.Convert.ChangeType(this.Id, property.PropertyType));

            // 将加载的对象存储到对象副本当中，用于提交的时候进行比对。
            if (this.Management.Command is IDocumentCommandObjectConversionProvider)
                ObjectConversionFactory.StorageObject(this.DataSource);

            this.RefreshText();

            // 广播变更通知
            this.Notification(status);
            //// 通知编辑面板操作成功
            //this.FormPanel.OnSuccess();
        }

        public override void Delete()
        {
            base.Delete();

            // 广播变更通知
            this.Notification(DocumentStatusChangeEnum.Delete);
        }

        /// <summary>
        /// 撤销更改。
        /// (类化单据没有撤销变更的过程。执行此函数时会关闭当前窗体。)
        /// </summary>
        public override void RejectChanges()
        {
            if (this.Management.Command is IDocumentCommandObjectConversionProvider)
            {
                var dataSource = ObjectConversionFactory.GetObject(this.DataSource);
                ObjectConversionFactory.RemoveObject(this.DataSource);
                ObjectConversionFactory.StorageObject(dataSource);
                this.LoadDataObject(dataSource);
            }
            else if (this.EditForm is System.Windows.Forms.Form frm)
            {
                frm.Close();
            }
        }

        /// <summary>
        /// 返回需要显示的标题。
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        /// <returns></returns>
        public virtual string CustomDisplayText(Entity item)
        {
            string title = string.Empty;
            MemberInfo memberInfo = item.GetType().GetMember(this.Management.Command.PrimaryName).First();
            if (memberInfo is PropertyInfo property)
                title = property.GetValue(this.DataSource)?.ToString();
            else if (memberInfo is FieldInfo field)
                title = field.GetValue(this.DataSource)?.ToString();
            return title;
        }
    }

    /// <summary>
    /// 单据编辑窗体的控制器。
    /// </summary>
    /// <typeparam name="Entity"></typeparam>
    /// <typeparam name="Source"></typeparam>
    public abstract class DocumentEditFormController<Entity, Source> : IDocumentEditFormController<Entity, Source>
    {



        /// <summary>
        /// 单据管理器。
        /// </summary>
        public DocumentManagement<Entity, Source> Management { get; set; }

        /// <summary>
        /// 编辑窗体的面板。
        /// </summary>
        public IDocumentEditForm<Entity, Source> FormPanel { get; set; }

        /// <summary>
        /// 绑定的数据源
        /// </summary>
        public Entity DataSource { get; set; }

        /// <summary>
        /// id值。
        /// </summary>
        public object Id { get; set; }

        /// <summary>
        /// 获取或设置是否允许编辑。
        /// </summary>
        bool IEditFormController.AllowEdit { get; set; }

        /// <summary>
        /// 获取或设置是否允许删除。
        /// </summary>
        bool IEditFormController.AllowDelete { get; set; }

        /// <summary>
        /// 提交自上次调用 AcceptChanges 以来对该数据源进行的所有更改。
        /// </summary>
        public abstract void AcceptChanges();

        /// <summary>
        /// 判断数据是否已被修改。
        /// </summary>
        public abstract bool HasChanges();

        /// <summary>
        /// 获取控或设置控制器所在的EditForm实例对象。
        /// </summary>
        public IEditForm EditForm { get; set; }

        /// <summary>
        /// 在状态变更时引发的事件。
        /// </summary>
        public event EventHandler StatusChanged;

        /// <summary>
        /// 点击创建的时候执行。
        /// </summary>
        public virtual void Create()
        {
            this.Management.ShowCreateForm();
        }

        /// <summary>
        /// 点击删除的时候执行。
        /// (通常情况下不需要重载,内部会自动调用 Command 的 Delete 函数。)
        /// </summary>
        public virtual void Delete()
        {
            this.Management.Command.Delete(this.DataSource);
        }

        IEditFormController IEditFormRoute.GetController()
        {
            return this;
        }

        Control IEditFormRoute.GetDataPanel()
        {
            return this.FormPanel as Control;
        }

        /// <summary>
        /// 创建需要编辑的数据对象。
        /// </summary>
        /// <param name="arguments"></param>
        public abstract Entity CreateDataObject(params object[] arguments);

        /// <summary>
        /// 创建临时数据,用于新增单据时的默认实例。
        /// </summary>
        /// <param name="arguments"></param>
        void IEditFormController.CreateDataObject(params object[] arguments)
        {
            this.Id = null;
            Entity source = this.CreateDataObject(arguments);
            this.LoadDataObject(source);
        }

        /// <summary>
        /// 新增需要编辑的数据对象
        /// </summary>
        /// <param name="arguments"></param>
        public virtual void NewDataObject(params object[] arguments)
        {
            this.Id = null;
            Entity source = this.CreateDataObject(arguments);
            this.LoadDataObject(source);
            if (this.EditForm is Marmat.Template.WinForm.EditForm editForm)
                editForm.Editor();
            else
                this.Editor();
        }

        /// <summary>
        /// 加载需要编辑的数据对象。
        /// <param name="arguments"></param>
        /// </summary>
        public virtual void LoadDataObject(params object[] arguments)
        {
            var command = this.Management.Command;
            Entity source = command.Load(this.Id);
            this.LoadDataObject(source);
        }

        /// <summary>
        /// 将数据重新附加给编辑窗体，以达到刷新界面的目的。
        /// </summary>
        public virtual void RefreshDataObject()
        {
            this.LoadDataObject(this.DataSource);
        }

        /// <summary>
        /// 发起状态变更的事件通知。
        /// </summary>
        public void OnStatusChanged()
        {
            this.StatusChanged?.Invoke(this, EventArgs.Empty);
        }
        /// <summary>
        /// 将数据附加给 FormPanel。
        /// </summary>
        /// <param name="source"></param>
        internal void LoadDataObject(Entity source)
        {
            if (source is null)
                throw new NullReferenceException("没有加载到数据,单据打开失败。");
            this.DataSource = source;
            this.FormPanel.Load(this.DataSource);
            this.OnStatusChanged();
            this.RefreshText();
        }

        /// <summary>
        /// 撤销更改。
        /// </summary>
        public abstract void RejectChanges();

        /// <summary>
        /// 保存。
        /// </summary>
        public virtual void Save()
        {
            if (this.Id is null)
            {
                var result = this.Management.Command.Create(this.DataSource);
                if (result is Entity)
                {
                    if (result is System.Data.DataRow row)
                        this.Id = row[this.Management.Command.PrimaryName];
                    else
                    {
                        Type type = result.GetType();
                        MemberInfo member = type.GetMember(this.Management.Command.PrimaryName).First();
                        if (member is FieldInfo field)
                            this.Id = field.GetValue(result);
                        else if (member is PropertyInfo property)
                            this.Id = property.GetValue(result);
                    }
                }
                else if (result is int or string)
                    this.Id = result;
            }
            else
                this.Management.Command.Write(this.DataSource);
        }

        /// <summary>
        /// 进入编辑模式(需要EditFormPanel支持Marmat.Foundation.IFormEditorStyle接口)
        /// </summary>
        public void Editor()
        {
            if (this.FormPanel is Marmat.Foundation.IEditFormEditorStyle editor)
                editor.Editor();
        }

        /// <summary>
        /// 进入预览模式(需要EditFormPanel支持Marmat.Foundation.IFormEditorStyle接口)
        /// </summary>
        public void Preview()
        {
            if (this.FormPanel is Marmat.Foundation.IEditFormEditorStyle editor)
                editor.Preview();
        }

        /// <summary>
        /// 通知视图窗体。
        /// </summary>
        /// <param name="status"></param>
        /// <param name="tag"></param>
        public virtual void Notification(DocumentStatusChangeEnum status, object tag = null)
        {
            // 广播变更通知
            foreach (var item in this.Management.viewFormCollection)
            {
                if (item is IDocumentViewFormNotification notification)
                    notification.Notification(this.Id, status, tag);
                else if (item is IDocumentViewFormNotification<Entity> Tnotification)
                    Tnotification.Notification(this.DataSource, status, tag);
            }
        }

        /// <summary>
        /// 刷新标题
        /// </summary>
        internal protected void RefreshText()
        {
            Control panel = this.FormPanel as Control;
            var command = this.Management.Command;
            string title = "";
            if (this.Id is null || string.IsNullOrEmpty(this.Id.ToString()))
            {
                title = "新建";
            }
            else
            {
                if (this is IEditFormDisplayText<Entity> customDisplay)
                    title = customDisplay.CustomDisplayText(this.DataSource);
                else
                {
                    string propertyName = command.PrimaryName;
                    if (this is IEditFormDisplayText display)
                        propertyName = display.DisplayName;

                    if (this.DataSource is System.Data.DataRow row)
                    {
                        title = row[propertyName]?.ToString();
                    }
                    else
                    {
                        MemberInfo memberInfo = this.DataSource.GetType().GetMember(propertyName).First();
                        if (memberInfo is PropertyInfo property)
                            title = property.GetValue(this.DataSource)?.ToString();
                        else if (memberInfo is FieldInfo field)
                            title = field.GetValue(this.DataSource)?.ToString();
                    }
                }
            }
            panel.Text = $"{this.Management.Text} : {title}";
        }
        /// <summary>
        /// 保存前的校验。
        /// </summary>
        /// <returns></returns>
        public virtual bool Verify()
        {
            return this.FormPanel.Verify();
        }
    }
}
